package com.xuecheng.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.learning.model.dto.CourseRecordDTO;
import com.xuecheng.api.learning.model.vo.ResourceUrlModel;
import com.xuecheng.api.order.model.pay.PayCodeUrlResult;
import com.xuecheng.api.search.model.dto.CoursePubIndexDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.learning.agent.CoursePubIndexApiAgent;
import com.xuecheng.learning.agent.MediaApiAgent;
import com.xuecheng.learning.common.constant.LearningErrorCode;
import com.xuecheng.learning.convert.CourseRecordConvert;
import com.xuecheng.learning.entity.CourseRecord;
import com.xuecheng.learning.mapper.CourseRecordMapper;
import com.xuecheng.learning.service.CourseRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 选课记录 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseRecordServiceImpl extends ServiceImpl<CourseRecordMapper, CourseRecord> implements CourseRecordService {

    @Autowired
    private CoursePubIndexApiAgent indexApiAgent;

    @Autowired
    private MediaApiAgent mediaApiAgent;


    @Autowired
    private CoursePubIndexApiAgent coursePubSearchApi;


    /*
    * 业务分析：
    *   1.判断关键数据
    *   2.根据条件查询用户的学习记录
    *   3.返回学习记录数据
    *       如果有数据返回
    *       如果没有返回空数据
    * */
    public CourseRecordDTO getRecordByCoursePubId(Long coursePubId, String username) {

        // 1.判断关键数据
        if (ObjectUtils.isEmpty(coursePubId)||
                StringUtil.isBlank(username)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        //  2.根据条件查询用户的学习记录(一个人对一门课只有一个学习记录)
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
        queryWrapper.eq(CourseRecord::getUserName, username);

        CourseRecord courseRecord = this.getOne(queryWrapper);



        //  3.返回学习记录数据
        CourseRecordDTO courseRecordDTO = null;
        if (ObjectUtils.isEmpty(courseRecord)) {
        //      如果没有返回空数据
            courseRecordDTO = new CourseRecordDTO();
        } else {
        //      如果有数据返回
            courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);
        }
        return courseRecordDTO;
    }

    /*
    * 业务分析：
    *   1.判断关键数据
    *       username  coursePubId
    *   2.判断业务数据
    *       课程发布信息
    *           判断是否存在
    *       课程计划数据获得
    *           从课程发布信息中
    *
    *   3.保存用户的学习记录
    *       学习记录创建信息要依据于课程是否收费
    *       如果课程是免费(无需操作)
    *           直接给用户创建学习记录
    *               默认章节为：第一章第一小节
    *               要给paid赋值为已经支付：0-此步骤可以忽略
    *
    *       如果课程是收费
    *           需要调用order服务获得用户是否对此课程已经支付-订单支付后的操作，由于是先执行订单服务修改订单状态，在没有问题的情况下再创建学习记录
    *               如果已经支付
    *                   创建学习记录
    *                       默认章节为：第一章第一小节
    *                       要给paid赋值为已经支付：1
    *
    *   4.将新增的数据查询并转化为dto并返回
    *
    *   PS：
    *       如果出现业务上出操作数据问题，本业务层直接抛出异常，无需返回RestResponse规范接口数据
             原因：本次的操作事务都是由Seata环境来控制，如果抛出异常，会是的整个的事务进行回滚操作
    *
    * */
    @Transactional
    public RestResponse<CourseRecordDTO> createCourseRecord4S(String username, Long coursePubId) {

        //1.判断关键数据
        //     username  coursePubId
        //
        //
        if (StringUtil.isBlank(username)||
                ObjectUtils.isEmpty(coursePubId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        // 2.判断业务数据
        //     课程发布信息
        //         判断是否存在
        RestResponse<CoursePubIndexDTO> pubIndexResponse = coursePubSearchApi.getCoursePubIndexById4s(coursePubId);

        if (!(pubIndexResponse.isSuccessful())) {
            ExceptionCast.castWithCodeAndDesc(pubIndexResponse.getCode(),pubIndexResponse.getMsg());
        }

        CoursePubIndexDTO coursePub = pubIndexResponse.getResult();


        //     课程计划数据获得
        //         从课程发布信息中
        String teachplanJsonString = coursePub.getTeachplan();

        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonString, TeachplanDTO.class);

        // 获得第一章节
        List<TeachplanDTO> secPlanTreeNodes = teachplanDTO.getTeachPlanTreeNodes();

        if (CollectionUtils.isEmpty(secPlanTreeNodes)) {
            ExceptionCast.cast(LearningErrorCode.E_202205);
        }
        TeachplanDTO secTeachplan = secPlanTreeNodes.get(0);

        if (ObjectUtils.isEmpty(secTeachplan)) {
            ExceptionCast.cast(LearningErrorCode.E_202205);
        }

        // 获得三级课程计划数据
        List<TeachplanDTO> thridTeachplans = secTeachplan.getTeachPlanTreeNodes();


        if (CollectionUtils.isEmpty(thridTeachplans)) {
            ExceptionCast.cast(LearningErrorCode.E_202206);
        }
        TeachplanDTO thridTeachplan = thridTeachplans.get(0);

        if (ObjectUtils.isEmpty(thridTeachplan)) {
            ExceptionCast.cast(LearningErrorCode.E_202206);
        }



        // 3.保存用户的学习记录
        //     学习记录创建信息要依据于课程是否收费
        String charge = coursePub.getCharge();



        //     如果课程是免费
        //         直接给用户创建学习记录
        //             默认章节为：第一章第一小节
        //             要给paid赋值为已经支付：0-此步骤可以忽略
        //     无需做实现

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)){
            //     如果课程是收费
            //         需要调用order服务获得用户是否对此课程已经支付

            // 如果学员已经有学习记录--收费课程支付后，要重置数据(用户体验不好，但是可以解决大部分的问题)
            LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CourseRecord::getUserName, username);
            queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);

            CourseRecord courseRecord = this.getOne(queryWrapper);

            boolean result = false;
            if (ObjectUtils.isEmpty(courseRecord)) {
                //             如果已经支付--判断用户是否已经支付
                //    无需操作-订单支付后的操作，由于是先执行订单服务修改订单状态，在没有问题的情况下再创建学习记录
                //                 创建学习记录
                //                     默认章节为：第一章第一小节
                //                     要给paid赋值为已经支付：1

                courseRecord = new CourseRecord();
                courseRecord.setUserName(username);
                courseRecord.setCompanyId(coursePub.getCompanyId());
                courseRecord.setCourseId(coursePub.getCourseId());
                courseRecord.setCoursePubId(coursePub.getIndexId());
                courseRecord.setCoursePubName(coursePub.getName());
                courseRecord.setTeachmode(coursePub.getTeachmode());
                courseRecord.setTeachplanId(thridTeachplan.getTeachPlanId());
                courseRecord.setTeachplanName(thridTeachplan.getPname());
                courseRecord.setPaid(new Integer(PayCodeUrlResult.PAIED));

                result = this.save(courseRecord);


            } else {
                //要重置数据(用户体验不好，但是可以解决大部分的问题)
                LambdaUpdateWrapper<CourseRecord> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(CourseRecord::getTeachplanId, thridTeachplan.getTeachPlanId());
                updateWrapper.set(CourseRecord::getTeachplanName, thridTeachplan.getPname());
                updateWrapper.set(CourseRecord::getPaid,new Integer(PayCodeUrlResult.PAIED) );
                updateWrapper.set(CourseRecord::getChangeDate, LocalDateTime.now());
                updateWrapper.eq(CourseRecord::getId,courseRecord.getId() );

                result = this.update(updateWrapper);
            }


            if (!result) {
                ExceptionCast.cast(LearningErrorCode.E_202204);
            }


        }

        // 4.将新增的数据查询并转化为dto并返回
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getUserName, username);
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);

        CourseRecord courseRecord = this.getOne(queryWrapper);

        CourseRecordDTO resultDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);

        return RestResponse.success(resultDTO);
    }


    /*
        *
        *   业务分析：
        *       1.判断关键数据
        *          Long coursePubId, Long mediaId, Long teachplanId, String username
        *       2.判断业务数据
        *           课程发布数据
        *               是否存在
        *           课程计划数据
        *               用户观看的三级课程计划数据是否存在（只有第三级的课程计划才可以观看）
        *
        *       3.判断用户是否有权限观看视频
                     课程是否收费
                         如果收费
                             判断观看的课程计划是否免费
                                如果免费
                                如果收费
                                  学习记录-isPaid
                          如果免费

                4.如果用户有权限观看
                  从媒资服务获得资源地址进行播放
        * */
    public ResourceUrlModel getResourceUrl(Long coursePubId, Long mediaId, Long teachplanId, String username) {

        ResourceUrlModel urlModel = new ResourceUrlModel();

        //1.判断关键数据
        //    Long coursePubId, Long mediaId, Long teachplanId, String username
        if (ObjectUtils.isEmpty(coursePubId)||
                ObjectUtils.isEmpty(mediaId)||
                ObjectUtils.isEmpty(teachplanId)||
                StringUtil.isBlank(username)
        ) {
            urlModel.wrong(CommonErrorCode.E_100101);
            return urlModel;
        }

        // 2.判断业务数据
        //     课程发布数据
        //         是否存在
        RestResponse<CoursePubIndexDTO> indexRestResponse = indexApiAgent.getCoursePubIndexById4s(coursePubId);

        if (!(indexRestResponse.isSuccessful())) {
            urlModel.wrong(indexRestResponse.getCode(),indexRestResponse.getMsg());
            return urlModel;
        }

        CoursePubIndexDTO coursePub = indexRestResponse.getResult();


        //     课程计划数据
        //         用户观看的三级课程计划数据是否存在（只有第三级的课程计划才可以观看）
        String treeNodesJsonString = coursePub.getTeachplan();

        // 获得的是一级课程计划
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(treeNodesJsonString, TeachplanDTO.class);

        // 二级课程计划集合数据
        List<TeachplanDTO> secTreeNodes = teachplanDTO.getTeachPlanTreeNodes();


        // 使用标记法
        TeachplanDTO selectedTreeNode = null;


        // 从二级课程计划数据中查询三级课程计划数据
        for (TeachplanDTO teachPlanTreeNode : secTreeNodes) {

            if (!(ObjectUtils.isEmpty(selectedTreeNode))) {
                break;
            }

            // 三级课程计划集合数据
            List<TeachplanDTO> thirdTreeNodes = teachPlanTreeNode.getTeachPlanTreeNodes();

            for (TeachplanDTO thirdTreeNode : thirdTreeNodes) {

                if (ObjectUtils.nullSafeEquals(teachplanId,thirdTreeNode.getTeachPlanId())) {
                    selectedTreeNode = thirdTreeNode;
                    break;
                }
            }
        }

        // 遍历后找不到课程计划数据，返回错误信息
        if (ObjectUtils.isEmpty(selectedTreeNode)) {
            urlModel.wrong(LearningErrorCode.E_202205);
            return urlModel;
        }


        // 3.判断用户是否有权限观看视频
        //      课程是否收费

        // 标识法
        boolean is_permission = false;

        String charge = coursePub.getCharge();

        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            // 收费课程
            //     判断观看的课程计划是否免费  免费：isPreview = 1  收费 ：isPreview = 0
            String isPreview = selectedTreeNode.getIsPreview();

            if (TeachplanDTO.IS_NOT_PREVIEW.equals(isPreview)) {

                //        如果收费
                //          学习记录-isPaid
                //     username coursePubid
                LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(CourseRecord::getUserName, username);
                queryWrapper.eq(CourseRecord::getCoursePubId,coursePubId);
                queryWrapper.eq(CourseRecord::getPaid,PayCodeUrlResult.PAIED);

                int count = this.count(queryWrapper);

                if (count > 0) {
                    is_permission = true;
                }

            } else {
                //        如果免费
                is_permission = true;
            }

        }else{
            // 免费课程
            is_permission = true;
        }


        // 4.如果用户有权限观看
        //   从媒资服务获得资源地址进行播放
        if (is_permission) {

            RestResponse<ResourceUrlModel> mediaResponse = mediaApiAgent.getResourceById4s(mediaId);

            if (!(mediaResponse.isSuccessful())) {
                urlModel.wrong(mediaResponse.getCode(),mediaResponse.getMsg());
                return urlModel;
            }

            ResourceUrlModel result = mediaResponse.getResult();
            return result;

        }

        // 用户最终还是无权访问，返回无权的错误信息
        urlModel.wrong(CommonErrorCode.E_100108);
        return urlModel;
    }

    @Override
    public Integer getCount(Long coursePubId) {
        LambdaQueryWrapper<CourseRecord> query = Wrappers.lambdaQuery(CourseRecord.class);
        query.eq(CourseRecord::getCoursePubId,coursePubId);
        return this.count(query);
    }


}
